package br.org.alexegidio.persistence;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;

/**
 * Implementação da interface GenericDAO específica para Hibernate
 * 
 * @author alexegidio@yahoo.com.br
 * 
 * @since 22/09/2010
 */
public class GenericDAOImpl<T> implements GenericDAO<T>, Serializable {

	private static final long serialVersionUID = 1L;
	private Class<T> domainClass;

	public GenericDAOImpl(Class<T> type) {
		this.domainClass = type;

	}

	private Session getSession() {
		return HibernateUtil.getSessionFactory().getCurrentSession();
	}

	public Class<T> getDomainClass() {
		return domainClass;
	}

	public void setDomainClass(Class<T> domainClass) {
		this.domainClass = domainClass;
	}

	public T save(T o) {

		getSession().saveOrUpdate(o);
		return o;
	}

	@SuppressWarnings("unchecked")
	public T load(Long id) {
		return (T) getSession().load(getDomainClass(), id);
	}

	@SuppressWarnings("unchecked")
	public List<T> listAll() {
		return getSession().createCriteria(getDomainClass()).list();
	}

	public boolean update(T transientObject) {
		try {
			getSession().update(transientObject);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	@SuppressWarnings("unchecked")
	public List<T> listPaginated(int maxResultsPerPage, int actualPage,
			String order) {

		return getSession().createCriteria(getDomainClass())
				.setMaxResults(maxResultsPerPage).setFirstResult(actualPage)
				.addOrder(Order.asc(order)).list();
	}

	public boolean delete(T persistentObject) {
		try {
			getSession().delete(persistentObject);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	@SuppressWarnings("unchecked")
	public T find(Long id) {

		return (T) getSession().get(getDomainClass(), id);
	}

	/**
	 * Retorna uma Lista de T
	 * 
	 * @param exampleInstance
	 *            = Um objeto de persistência para ser utilizado como parâmetro
	 * @param excludeProperties
	 *            Um array de String com as propriedades não utilizadas na busca
	 */
	@SuppressWarnings("unchecked")
	public List<T> listByExample(T exampleInstance, String[] excludeProperties) {
		Criteria crit = getSession().createCriteria(getDomainClass());
		Example example = Example.create(exampleInstance);
		for (String exclude : excludeProperties) {
			example.excludeProperty(exclude);
		}
		crit.add(example);

		return crit.list();
	}

}
